/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package SemanticoPacote;

import SemanticoPacote.TratamentoErroSemantico.ErroSemantico;
import SintaticoPacote.Tipos;
import com.sun.corba.se.spi.copyobject.CopierManager;
import compilador_full.TabelaSimbolos;
import java.util.Hashtable;

/**
 *
 * @author Larissa
 */
public class declaracaoMetodos {


     public Hashtable<Integer, String> metodos = new Hashtable<Integer, String>();

    public void declaraMetodos(TabelaSimbolos tabelaSimbolos, int indice) {


        declaracaoStructs verificaDeclaracaoStruct = new declaracaoStructs();
        declaraVariaveis verificaDeclaracaoVariaveis = new declaraVariaveis();
        cmd verificaCmd = new cmd();
        chamadaDeFuncao verificaChamadaDeFuncao = new chamadaDeFuncao(tabelaSimbolos);


        String tipoRetorno = tabelaSimbolos.getLookahead();
        tabelaSimbolos.soConsome(); //consome tipo de retorno

        if (tabelaSimbolos.getLookahead().equals("*")) {
            tabelaSimbolos.soConsome(); // consome o * se ele aparecer
        }

        //pergunta se já existe um metodo com esse nome
        if(this.jaContemAqueleMetodo(tabelaSimbolos.getLookahead(),indice)){
            if(!tabelaSimbolos.verificaDuplicidadeDeMetodo(tabelaSimbolos.getLookahead()))
            {
                System.out.println("ERRO SEMANTICO - " + tabelaSimbolos.getLookahead() + " na linha " + tabelaSimbolos.getLinha() + " metodo ja declarado");
                ErroSemantico.getInstance().getTabelaErros().add("Erro Semântico na linha " +tabelaSimbolos.getLinha() + ". Descrição: O método já foi declarado");
            }
        }

        String nomeMetodo = tabelaSimbolos.getLookahead(); // VOu precisar do nome do metodo para passar pro ChamaFuncao.
        tabelaSimbolos.soConsome(); //consome nome do metodo
        tabelaSimbolos.soConsome(); //consome o (

        //<parametros> ::= <tipos> [ * ] <nome> { , <tipos> [ * ] <nome>}
        while (!(tabelaSimbolos.getLookahead().equals(")"))) { // consome todos os parâmentros, até achar o )
                       System.out.println("no metodo " + tabelaSimbolos.getLookahead());
                       tabelaSimbolos.soConsome();

                       if(tabelaSimbolos.getLookahead().equals("*")){
                           tabelaSimbolos.soConsome();
                       }
                       System.out.println("no metodo " + tabelaSimbolos.getLookahead());
                       if(tabelaSimbolos.verificaSeFoiDeclaradoComoGlobal(tabelaSimbolos.getLookahead())){
                           System.out.println("ERRO SEMANTICO - " + tabelaSimbolos.getLookahead() + " na linha " + tabelaSimbolos.getLinha() + " variavel do parametro ja declarado");
                           ErroSemantico.getInstance().getTabelaErros().add("Erro Semântico na linha " +tabelaSimbolos.getLinha() + ". Descrição: A variável já foi declarado");
                       }
                       tabelaSimbolos.soConsome();

                       System.out.println("no metodo " + tabelaSimbolos.getLookahead());
                       if(tabelaSimbolos.getLookahead().equals(","))
                           tabelaSimbolos.soConsome();
        }

        tabelaSimbolos.soConsome(); // consome o parêntese )
        tabelaSimbolos.soConsome();// Consome o {

        while (tabelaSimbolos.getLookahead().equals("typedef") ||
                tabelaSimbolos.getLookahead().equals("struct") ||
                Tipos.apenasCompara(tabelaSimbolos)) {


            if (tabelaSimbolos.getLookahead().equals("typedef")) {
                if (tabelaSimbolos.superLookahead(1).equals("struct")) {
                   // int v = analise.getIndiceStruct();
                    //System.out.println("v: " + v);
                    verificaDeclaracaoStruct.declaraStructs(tabelaSimbolos);


                } else if (Tipos.apenasCompara(tabelaSimbolos)) {
                    verificaDeclaracaoVariaveis.declaraVariaveis(tabelaSimbolos, nomeMetodo);



                } else if (tabelaSimbolos.getLookahead().equals("struct")) {
                     //int v1 = analise.getIndiceStruct();
                    // System.out.println("v1: " + v1);
                    verificaDeclaracaoStruct.declaraStructs(tabelaSimbolos);
                }

            } else if (Tipos.apenasCompara(tabelaSimbolos)) {
                if(tabelaSimbolos.getTipo().equals("identificador"))
                {
                    tabelaSimbolos.soConsome();//Consome identificador
                    tabelaSimbolos.soConsome();//Consome o =
                    tabelaSimbolos.soConsome();//Consome o que vem depois do igual
                    tabelaSimbolos.soConsome();//Consome o ;
                }
                else if (tabelaSimbolos.superTipo(1).equals("identificador")) {
                    verificaDeclaracaoVariaveis.declaraVariaveis(tabelaSimbolos, nomeMetodo);
                } else if (tabelaSimbolos.superLookahead(1).equals("*")) {
                    verificaDeclaracaoVariaveis.declaraVariaveis(tabelaSimbolos, nomeMetodo);
                }
            }


        }


        while (tabelaSimbolos.getLookahead().equals("*") |
                tabelaSimbolos.getLookahead().equals("printf") |
                tabelaSimbolos.getLookahead().equals("scanf") |
                tabelaSimbolos.getLookahead().equals("do") |
                tabelaSimbolos.getLookahead().equals("while") |
                tabelaSimbolos.getLookahead().equals("for") |
                tabelaSimbolos.getLookahead().equals("if") |
                tabelaSimbolos.getTipo().equals("identificador")) {

            verificaCmd.sintaxeCmd(tabelaSimbolos, nomeMetodo);
        }


        tabelaSimbolos.soConsome(); //consome return
        String compara = Utils.tipoValor(tabelaSimbolos.getLookahead());
        if(tabelaSimbolos.getLookahead().equals("true") || tabelaSimbolos.getLookahead().equals("false")){
        
        if(!tipoRetorno.equals(compara))
        {
                 System.out.println("Erro Semântico na linha " +tabelaSimbolos.getLinha() + ". Descrição: "+ tabelaSimbolos.getLookahead() + " Tipo de retorno incompativel");
                 ErroSemantico.getInstance().getTabelaErros().add("Erro Semântico na linha " +tabelaSimbolos.getLinha() + ". Descrição: "+ tabelaSimbolos.getLookahead() + " Tipo de retorno incompativel");
        }

        }
        
        else if(tabelaSimbolos.getTipo().equals("numero"))
        {
            String compara2 = Utils.tipoValor(tabelaSimbolos.getLookahead());
            if(!tipoRetorno.equals(compara2))
            {
                System.out.println("Erro Semântico na linha " +tabelaSimbolos.getLinha() + ". Descrição: "+ tabelaSimbolos.getLookahead() + " Tipo de retorno incompativel");
                ErroSemantico.getInstance().getTabelaErros().add("Erro Semântico na linha " +tabelaSimbolos.getLinha() + ". Descrição: "+ tabelaSimbolos.getLookahead() + " Tipo de retorno incompativel");
                compara2="";
            }
            else
                compara2="";
        }
        else if(tabelaSimbolos.getTipo().equals("identificador"))
        {
            if(!tabelaSimbolos.verificaSeVariavelFoiDeclarada(tabelaSimbolos.getLookahead()))
            {
                System.out.println("Erro Semântico na linha " +tabelaSimbolos.getLinha() + ". Descrição: "+ tabelaSimbolos.getLookahead() + " variavel nao declarada");
                ErroSemantico.getInstance().getTabelaErros().add("Erro Semântico na linha " +tabelaSimbolos.getLinha() + ". Descrição: "+ tabelaSimbolos.getLookahead() + " variavel nao declarada");
            }
            String tipoVariavel = tabelaSimbolos.RetornaTipoDeGlobalDeclarada(tabelaSimbolos.getLookahead());
            if(tipoVariavel.equals(""))
            {
               tipoVariavel = tabelaSimbolos.RetornaTipoDeLocalDeclarada(tabelaSimbolos.getLookahead(),nomeMetodo);
            }
            if(!tipoVariavel.equals(tipoRetorno))
            {
                System.out.println("Erro Semântico na linha " +tabelaSimbolos.getLinha() + ". Descrição: "+ tabelaSimbolos.getLookahead() + " Tipo de retorno incompativel");
                ErroSemantico.getInstance().getTabelaErros().add("Erro Semântico na linha " +tabelaSimbolos.getLinha() + ". Descrição: "+ tabelaSimbolos.getLookahead() + " Tipo de retorno incompativel");
            }
        }
        compara = "";
        


        if (tabelaSimbolos.getTipo().equals("numero")) {
            tabelaSimbolos.reconhecer(tabelaSimbolos.getLookahead());
        } //COnsertar. Aqui tem que retornar verdadeiro se o elemento for um boolean
        else if (tabelaSimbolos.getLookahead().equals("true") | tabelaSimbolos.getLookahead().equals("false")) {
            tabelaSimbolos.reconhecer(tabelaSimbolos.getLookahead());
        } //Nosso léxico não classifica como caractere.
        //Caso venha um return 'a', esse 'a' ele considera como identificador, logo
        //essa condição ja esta sendo atendida no else if seguinte.
        else if (tabelaSimbolos.getTipo().equals("frase")) {
            // Consertar. Tem que retornar verdadeiro se o elemento for um caracter
            tabelaSimbolos.soConsome();
        } else if (tabelaSimbolos.getTipo().equals("identificador") &&
                tabelaSimbolos.superLookahead(1).equals(";")) {
            tabelaSimbolos.reconhecer(tabelaSimbolos.getLookahead());
        } else if (tabelaSimbolos.getTipo().equals("numero") ||
                tabelaSimbolos.getTipo().equals("identificador") ||
                tabelaSimbolos.getLookahead().equals("(")) {

            verificaChamadaDeFuncao.chamaFuncao(nomeMetodo); // falar com quem fez isso. by Igo

        }




        tabelaSimbolos.soConsome();//consome ;
        tabelaSimbolos.soConsome();//consome }


    }


   public boolean jaContemAqueleMetodo(String metodo, int indice){


        if(!metodos.contains(metodo)){
            metodos.put(indice, metodo);
            return false;// retorna false pq nao tinha
        }
        else
            return true;//ja contém aquela constante
 
    }


}

